"""

Roket Secure Language - Builtin Class (Map)

"""

from Builtins import BuiltinC, BuiltinF
from RSB import Obj
import math

class MathBIC(BuiltinC):
	def __init__(self, type):
		# Call the parent function
		super(MathBIC, self).__init__(type)
		
		# Then associate our functions
		self.constructor = MathBICC("__init__", ["self"])
		self.functions["sin"] = SinBIF("sin", ["self", "val"]);
		self.functions["cos"] = CosBIF("cos", ["self", "val"]);
		self.functions["tan"] = TanBIF("tan", ["self", "val"]);
		self.functions["asin"] = AsinBIF("asin", ["self", "val"]);
		self.functions["acos"] = AcosBIF("acos", ["self", "val"]);
		self.functions["atan"] = AtanBIF("atan", ["self", "val"]);
		self.functions["atan2"] = Atan2BIF("atan2", ["self", "y", "x"]);
		self.functions["sinh"] = SinhBIF("sinh", ["self", "val"]);
		self.functions["cosh"] = CoshBIF("cosh", ["self", "val"]);
		self.functions["tanh"] = TanhBIF("tanh", ["self", "val"]);
		self.functions["asinh"] = AsinhBIF("asinh", ["self", "val"]);
		self.functions["acosh"] = AcoshBIF("acosh", ["self", "val"]);
		self.functions["atanh"] = AtanhBIF("atanh", ["self", "val"]);
		
		self.functions["ceil"] = CeilBIF("tan", ["self", "val"]);
		self.functions["floor"] = FloorBIF("tan", ["self", "val"]);
		self.functions["round"] = RoundBIF("tan", ["self", "val"]);
		self.functions["abs"] = AbsBIF("tan", ["self", "val"]);
		self.functions["mod"] = ModBIF("tan", ["self", "x", "y"]);
		self.functions["isinf"] = IsInfBIF("tan", ["self", "val"]);
		self.functions["isnan"] = IsNanBIF("tan", ["self", "val"]);
		self.functions["exp"] = ExpBIF("tan", ["self", "val"]);
		self.functions["log"] = LogBIF("tan", ["self", "val"]);
		self.functions["logb"] = LogbBIF("tan", ["self", "val", "base"]);
		self.functions["log1p"] = Log1pBIF("tan", ["self", "val"]);
		self.functions["log10"] = Log10BIF("tan", ["self", "val"]);
		self.functions["sqrt"] = SqrtBIF("tan", ["self", "val"]);
		self.functions["hypot"] = HypotBIF("hypot", ["self", "x", "y"]);
		self.functions["degrees"] = DegreesBIF("degrees", ["self", "val"]);
		self.functions["radians"] = RadiansBIF("radians", ["self", "val"]);
		
		self.variables["pi"] = math.pi;
		self.variables["e"] = math.e;

class MathBICC(BuiltinF):
	def execute(self, engine, args):
		# Nothing required for this class.
		pass

# Standard trigonometry functions
class SinBIF(BuiltinF):
	def execute(self, engine, args):
		if (not isinstance(args[1], float)):
			self.error(engine, "Argument #1 '" + str(args[1]) + "' is not a number.");
		else:
			self.BCReturn(math.sin(args[1]), engine)

class CosBIF(BuiltinF):
	def execute(self, engine, args):
		if (not isinstance(args[1], float)):
			self.error(engine, "Argument #1 '" + str(args[1]) + "' is not a number.");
		else:
			self.BCReturn(math.cos(args[1]), engine)

class TanBIF(BuiltinF):
	def execute(self, engine, args):
		if (not isinstance(args[1], float)):
			self.error(engine, "Argument #1 '" + str(args[1]) + "' is not a number.");
		else:
			self.BCReturn(math.tan(args[1]), engine)

class AsinBIF(BuiltinF):
	def execute(self, engine, args):
		if (not isinstance(args[1], float)):
			self.error(engine, "Argument #1 '" + str(args[1]) + "' is not a number.");
		else:
			self.BCReturn(math.asin(args[1]), engine)

class AcosBIF(BuiltinF):
	def execute(self, engine, args):
		if (not isinstance(args[1], float)):
			self.error(engine, "Argument #1 '" + str(args[1]) + "' is not a number.");
		else:
			self.BCReturn(math.acos(args[1]), engine)

class AtanBIF(BuiltinF):
	def execute(self, engine, args):
		if (not isinstance(args[1], float)):
			self.error(engine, "Argument #1 '" + str(args[1]) + "' is not a number.");
		else:
			self.BCReturn(math.atan(args[1]), engine)

class Atan2BIF(BuiltinF):
	def execute(self, engine, args):
		if (not isinstance(args[1], float)):
			self.error(engine, "Argument #1 '" + str(args[1]) + "' is not a number.");
		elif (not isinstance(args[2], float)):
			self.error(engine, "Argument #2 '" + str(args[2]) + "' is not a number.");
		else:
			self.BCReturn(math.atan2(args[1], args[2]), engine)

class HypotBIF(BuiltinF):
	def execute(self, engine, args):
		if (not isinstance(args[1], float)):
			self.error(engine, "Argument #1 '" + str(args[1]) + "' is not a number.");
		elif (not isinstance(args[2], float)):
			self.error(engine, "Argument #2 '" + str(args[2]) + "' is not a number.");
		else:
			self.BCReturn(math.hypot(args[1], args[2]), engine)

# Hyperbola functions
class SinhBIF(BuiltinF):
	def execute(self, engine, args):
		if (not isinstance(args[1], float)):
			self.error(engine, "Argument #1 '" + str(args[1]) + "' is not a number.");
		else:
			self.BCReturn(math.sinh(args[1]), engine)

class CoshBIF(BuiltinF):
	def execute(self, engine, args):
		if (not isinstance(args[1], float)):
			self.error(engine, "Argument #1 '" + str(args[1]) + "' is not a number.");
		else:
			self.BCReturn(math.cosh(args[1]), engine)

class TanhBIF(BuiltinF):
	def execute(self, engine, args):
		if (not isinstance(args[1], float)):
			self.error(engine, "Argument #1 '" + str(args[1]) + "' is not a number.");
		else:
			self.BCReturn(math.tanh(args[1]), engine)

class AsinhBIF(BuiltinF):
	def execute(self, engine, args):
		if (not isinstance(args[1], float)):
			self.error(engine, "Argument #1 '" + str(args[1]) + "' is not a number.");
		else:
			self.BCReturn(math.asinh(args[1]), engine)

class AcoshBIF(BuiltinF):
	def execute(self, engine, args):
		if (not isinstance(args[1], float)):
			self.error(engine, "Argument #1 '" + str(args[1]) + "' is not a number.");
		else:
			self.BCReturn(math.acosh(args[1]), engine)

class AtanhBIF(BuiltinF):
	def execute(self, engine, args):
		if (not isinstance(args[1], float)):
			self.error(engine, "Argument #1 '" + str(args[1]) + "' is not a number.");
		else:
			self.BCReturn(math.atanh(args[1]), engine)

# Rounding functions
class CeilBIF(BuiltinF):
	def execute(self, engine, args):
		if (not isinstance(args[1], float)):
			self.error(engine, "Argument #1 '" + str(args[1]) + "' is not a number.");
		else:
			self.BCReturn(math.ceil(args[1]), engine)

class FloorBIF(BuiltinF):
	def execute(self, engine, args):
		if (not isinstance(args[1], float)):
			self.error(engine, "Argument #1 '" + str(args[1]) + "' is not a number.");
		else:
			self.BCReturn(math.floor(args[1]), engine)

class RoundBIF(BuiltinF):
	def execute(self, engine, args):
		if (not isinstance(args[1], float)):
			self.error(engine, "Argument #1 '" + str(args[1]) + "' is not a number.");
		else:
			self.BCReturn(math.round(args[1]), engine)

# Absolute & modulo functions
class AbsBIF(BuiltinF):
	def execute(self, engine, args):
		if (not isinstance(args[1], float)):
			self.error(engine, "Argument #1 '" + str(args[1]) + "' is not a number.");
		else:
			self.BCReturn(math.abs(args[1]), engine)

class ModBIF(BuiltinF):
	def execute(self, engine, args):
		if (not isinstance(args[1], float)):
			self.error(engine, "Argument #1 '" + str(args[1]) + "' is not a number.");
		elif (not isinstance(args[2], float)):
			self.error(engine, "Argument #2 '" + str(args[2]) + "' is not a number.");
		else:
			self.BCReturn(math.mod(args[1], args[2]), engine)

# Infinity / NaN functions
class IsInfBIF(BuiltinF):
	def execute(self, engine, args):
		if (not isinstance(args[1], float)):
			self.error(engine, "Argument #1 '" + str(args[1]) + "' is not a number.");
		else:
			self.BCReturn(math.isinf(args[1]), engine)

class IsNanBIF(BuiltinF):
	def execute(self, engine, args):
		if (not isinstance(args[1], float)):
			self.error(engine, "Argument #1 '" + str(args[1]) + "' is not a number.");
		else:
			self.BCReturn(math.isnan(args[1]), engine)

# Power and logarithm functions
class ExpBIF(BuiltinF):
	def execute(self, engine, args):
		if (not isinstance(args[1], float)):
			self.error(engine, "Argument #1 '" + str(args[1]) + "' is not a number.");
		else:
			self.BCReturn(math.exp(args[1]), engine)

class LogBIF(BuiltinF):
	def execute(self, engine, args):
		if (not isinstance(args[1], float)):
			self.error(engine, "Argument #1 '" + str(args[1]) + "' is not a number.");
		else:
			self.BCReturn(math.log(args[1]), engine)

class LogbBIF(BuiltinF):
	def execute(self, engine, args):
		if (not isinstance(args[1], float)):
			self.error(engine, "Argument #1 '" + str(args[1]) + "' is not a number.");
		elif (not isinstance(args[2], float)):
			self.error(engine, "Argument #2 '" + str(args[2]) + "' is not a number.");
		else:
			self.BCReturn(math.log(args[1], args[2]), engine)

class Log1pBIF(BuiltinF):
	def execute(self, engine, args):
		if (not isinstance(args[1], float)):
			self.error(engine, "Argument #1 '" + str(args[1]) + "' is not a number.");
		else:
			self.BCReturn(math.log1p(args[1]), engine)

class Log10BIF(BuiltinF):
	def execute(self, engine, args):
		if (not isinstance(args[1], float)):
			self.error(engine, "Argument #1 '" + str(args[1]) + "' is not a number.");
		else:
			self.BCReturn(math.log10(args[1]), engine)

class SqrtBIF(BuiltinF):
	def execute(self, engine, args):
		if (not isinstance(args[1], float)):
			self.error(engine, "Argument #1 '" + str(args[1]) + "' is not a number.");
		else:
			self.BCReturn(math.sqrt(args[1]), engine)

# Conversion functions
class DegreesBIF(BuiltinF):
	def execute(self, engine, args):
		if (not isinstance(args[1], float)):
			self.error(engine, "Argument #1 '" + str(args[1]) + "' is not a number.");
		else:
			self.BCReturn(math.degrees(args[1]), engine)

class RadiansBIF(BuiltinF):
	def execute(self, engine, args):
		if (not isinstance(args[1], float)):
			self.error(engine, "Argument #1 '" + str(args[1]) + "' is not a number.");
		else:
			self.BCReturn(math.radians(args[1]), engine)